package setup

import (
	"fmt"

	"github.com/zitadel/zitadel/internal/api/scim/metadata"
	"github.com/zitadel/zitadel/internal/database"
	"github.com/zitadel/zitadel/internal/domain"
	"github.com/zitadel/zitadel/internal/migration"
	"github.com/zitadel/zitadel/internal/query/projection"
	"github.com/zitadel/zitadel/internal/serviceping"
)

// triggerSteps defines the repeatable migrations that set up triggers
// for counting resources in the database.
func triggerSteps(db *database.DB) []migration.RepeatableMigration {
	return []migration.RepeatableMigration{
		// Delete parent count triggers for instances and organizations
		migration.DeleteParentCountsTrigger(db,
			projection.InstanceProjectionTable,
			domain.CountParentTypeInstance,
			projection.InstanceColumnID,
			projection.InstanceColumnID,
			serviceping.ResourceCountInstance,
		),
		migration.DeleteParentCountsTrigger(db,
			projection.OrgProjectionTable,
			domain.CountParentTypeOrganization,
			projection.OrgColumnInstanceID,
			projection.OrgColumnID,
			serviceping.ResourceCountOrganization,
		),

		// Count triggers for all the resources
		migration.CountTrigger(db,
			projection.OrgProjectionTable,
			domain.CountParentTypeInstance,
			projection.OrgColumnInstanceID,
			projection.OrgColumnInstanceID,
			serviceping.ResourceCountOrganization,
		),
		migration.CountTrigger(db,
			projection.ProjectProjectionTable,
			domain.CountParentTypeOrganization,
			projection.ProjectColumnInstanceID,
			projection.ProjectColumnResourceOwner,
			serviceping.ResourceCountProject,
		),
		migration.CountTrigger(db,
			projection.UserTable,
			domain.CountParentTypeOrganization,
			projection.UserInstanceIDCol,
			projection.UserResourceOwnerCol,
			serviceping.ResourceCountUser,
		),
		migration.CountTriggerConditional(db,
			projection.UserTable,
			domain.CountParentTypeOrganization,
			projection.UserInstanceIDCol,
			projection.UserResourceOwnerCol,
			serviceping.ResourceCountUserMachine,
			false, // the user type cannot change, so we do not need to track updates
			&migration.TriggerCondition{
				Column: projection.UserTypeCol,
				// since we marshal the value into and from json,
				// we directly use the float64 value to prevent issues with the comparison of the previous migration
				Value: float64(2),
			},
		),
		migration.CountTrigger(db,
			projection.InstanceMemberProjectionTable,
			domain.CountParentTypeInstance,
			projection.MemberInstanceID,
			projection.MemberResourceOwner,
			serviceping.ResourceCountIAMAdmin,
		),
		migration.CountTrigger(db,
			projection.IDPTable,
			domain.CountParentTypeInstance,
			projection.IDPInstanceIDCol,
			projection.IDPInstanceIDCol,
			serviceping.ResourceCountIdentityProvider,
		),
		migration.CountTrigger(db,
			projection.IDPTemplateLDAPTable,
			domain.CountParentTypeInstance,
			projection.LDAPInstanceIDCol,
			projection.LDAPInstanceIDCol,
			serviceping.ResourceCountIdentityProviderLDAP,
		),
		migration.CountTrigger(db,
			projection.ActionTable,
			domain.CountParentTypeInstance,
			projection.ActionInstanceIDCol,
			projection.ActionInstanceIDCol,
			serviceping.ResourceCountActionV1,
		),
		migration.CountTrigger(db,
			projection.ExecutionTable,
			domain.CountParentTypeInstance,
			projection.ExecutionInstanceIDCol,
			projection.ExecutionInstanceIDCol,
			serviceping.ResourceCountActionExecution,
		),
		migration.CountTrigger(db,
			fmt.Sprintf("%s_%s", projection.ExecutionTable, projection.ExecutionTargetSuffix),
			domain.CountParentTypeInstance,
			projection.ExecutionTargetInstanceIDCol,
			projection.ExecutionTargetInstanceIDCol,
			serviceping.ResourceCountActionExecutionTarget,
		),
		migration.CountTrigger(db,
			projection.LoginPolicyTable,
			domain.CountParentTypeInstance,
			projection.LoginPolicyInstanceIDCol,
			projection.LoginPolicyInstanceIDCol,
			serviceping.ResourceCountLoginPolicy,
		),
		migration.CountTriggerConditional(db,
			projection.LoginPolicyTable,
			domain.CountParentTypeInstance,
			projection.LoginPolicyInstanceIDCol,
			projection.LoginPolicyInstanceIDCol,
			serviceping.ResourceCountEnforceMFA,
			true,
			&migration.OrCondition{
				Conditions: []migration.TriggerCondition{
					{Column: projection.LoginPolicyForceMFACol, Value: true},
					{Column: projection.LoginPolicyForceMFALocalOnlyCol, Value: true},
				},
			},
		),
		migration.CountTrigger(db,
			projection.PasswordComplexityTable,
			domain.CountParentTypeInstance,
			projection.ComplexityPolicyInstanceIDCol,
			projection.ComplexityPolicyInstanceIDCol,
			serviceping.ResourceCountPasswordComplexityPolicy,
		),
		migration.CountTrigger(db,
			projection.PasswordAgeTable,
			domain.CountParentTypeInstance,
			projection.AgePolicyInstanceIDCol,
			projection.AgePolicyInstanceIDCol,
			serviceping.ResourceCountPasswordExpiryPolicy,
		),
		migration.CountTrigger(db,
			projection.LockoutPolicyTable,
			domain.CountParentTypeInstance,
			projection.LockoutPolicyInstanceIDCol,
			projection.LockoutPolicyInstanceIDCol,
			serviceping.ResourceCountLockoutPolicy,
		),
		migration.CountTriggerConditional(db,
			projection.NotificationPolicyProjectionTable,
			domain.CountParentTypeInstance,
			projection.NotificationPolicyColumnInstanceID,
			projection.NotificationPolicyColumnInstanceID,
			serviceping.ResourceCountPasswordChangeNotification,
			true,
			&migration.TriggerCondition{
				Column: projection.NotificationPolicyColumnPasswordChange,
				Value:  true,
			},
		),
		migration.CountTriggerConditional(db,
			projection.UserMetadataProjectionTable,
			domain.CountParentTypeOrganization,
			projection.UserMetadataColumnInstanceID,
			projection.LockoutPolicyResourceOwnerCol,
			serviceping.ResourceCountScimProvisionedUser,
			false, // the key cannot change, so we do not need to track updates
			&migration.TriggerCondition{
				Column: projection.UserMetadataColumnKey,
				Value:  metadata.KeyEmails,
			},
		),
	}
}
